package middleware

import (
	"context"
	"encoding/json"
	"fmt"
	"gin/app/http/global"
	user2 "gin/app/http/model/user"
	"gin/app/http/response"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"strings"
)

// CheckToken 验证 token，校验通过后把 user_id、user_name 写入上下文
func CheckToken(c *gin.Context) {
	// 1. 优先从 Context 读取（如果之前某个中间件已经放入）
	if t, ok := c.Get("token"); ok {
		if ts, ok2 := t.(string); ok2 && ts != "" {
			handleToken(c, ts)
			return
		}
	}

	// 2. 从 Authorization Header 读取
	authHeader := c.GetHeader("Authorization")
	if authHeader != "" {
		// 支持 "Bearer xxxxx" 或直接 token
		if strings.HasPrefix(authHeader, "Bearer ") {
			token := strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer "))
			if token != "" {
				handleToken(c, token)
				return
			}
		} else {
			token := strings.TrimSpace(authHeader)
			if token != "" {
				handleToken(c, token)
				return
			}
		}
	}

	// 3. 从查询参数读取（可选，便于调试）
	if qtoken := c.Query("token"); qtoken != "" {
		handleToken(c, qtoken)
		return
	}

	// token 未找到
	response.Fail(c, "token校验失败！", gin.H{"message": "token缺失"})
	c.Abort()
	return
}

// handleToken 真正校验 token 并注入上下文
func handleToken(c *gin.Context, accessToken string) {
	prefix := viper.GetString("redis.prefix")
	if prefix == "" {
		prefix = "app" // 默认前缀，按需修改
	}

	Rdb := global.Rdb
	ctx := context.Background() // 如果你有 request 上下文需要传入，请替换为 c.Request.Context()

	// 从 Redis 哈希表读取用户信息（假设存储格式为 HSET prefix_user_info token user_json）
	userInfoJSON, err := Rdb.HGet(ctx, prefix+"_user_info", accessToken).Result()
	if err != nil {
		// Redis 未找到或其他错误
		// 为了排查，打印错误日志（生产请改为日志系统）
		fmt.Printf("[CheckToken] HGet err: %v\n", err)
		response.Fail(c, "token校验失败！", gin.H{"message": "token不存在或已过期"})
		c.Abort()
		return
	}
	if userInfoJSON == "" {
		response.Fail(c, "token校验失败！", gin.H{"message": "token无效"})
		c.Abort()
		return
	}

	// 反序列化用户信息（确保模型字段匹配）
	var user user2.UserModel
	if err := json.Unmarshal([]byte(userInfoJSON), &user); err != nil {
		fmt.Printf("[CheckToken] Unmarshal err: %v\n", err)
		response.Fail(c, "用户信息解析失败！", gin.H{"error": err.Error()})
		c.Abort()
		return
	}

	// 校验对应的用户 token 是否存在（例如：SET prefix_user_token_<uid> token）
	userTokenKey := fmt.Sprintf("%s_user_token_%d", prefix, user.UserId)
	exists, err := Rdb.Exists(ctx, userTokenKey).Result()
	if err != nil {
		fmt.Printf("[CheckToken] Exists err: %v\n", err)
		response.Fail(c, "token 校验异常", gin.H{"error": err.Error()})
		c.Abort()
		return
	}
	if exists == 0 {
		// token 已失效：清理并返回
		_ = Rdb.HDel(ctx, prefix+"_user_info", accessToken)
		_ = Rdb.Del(ctx, userTokenKey)
		response.Fail(c, "token失效！", gin.H{"message": "请重新登录"})
		c.Abort()
		return
	}

	// ✅ 成功：把用户信息写入 Gin 上下文，后续中间件/控制器可用
	c.Set("user_id", user.UserId)
	// 如果你需要 username，email 等也可以一起写入
	c.Set("user_name", user.UserName)
	// 可选：把 token 也写入上下文
	c.Set("token", accessToken)

	fmt.Printf("[CheckToken] 验证通过 user_id=%d user_name=%s\n", user.UserId, user.UserName)
	c.Next()
}
